﻿#include <SDL/SDL_image.h>
#include <sstream>
#include "Utils\ResGroupManager.h"
#include "Utils\Color.h"
#include "NumberGeneratorScreen.h"
#include "ResultScreen.h"
#include "HelpScreen.h"

using namespace SDL::UTILS;
using namespace SDL::ELEMENTS;

NumberGeneratorArgs::NumberGeneratorArgs(SDL_Surface* _screen, SDL_Event* _event) : MyScreenArgs(_screen, _event)
{
}

NumberGeneratorArgs::~NumberGeneratorArgs()
{
}



std::string const NumberGeneratorScreen::PATH = CST::MOD_PATH + "number_generator\\";

NumberGeneratorScreen::NumberGeneratorScreen() : IScreen(),
	m_font("C:\\Windows\\Fonts\\arial.ttf", 24), m_possibilitiesLabel(NULL), m_timeLabel(NULL), m_nbLabel(NULL),
	m_pbStart(NULL), m_pbStop(NULL), m_pbBack(NULL), m_pbHelp(NULL), m_valueLabel(NULL),
	m_config(2, 30, 0), m_generator(NULL),
	m_popUpScreen(NULL), m_popUpArgs(NULL)
{
	m_surface.SetSurface(IMG_Load(std::string(NumberGeneratorScreen::PATH + "images\\background.png").c_str()));
	this->InitElements();
	m_pbStop->SetDisabled(true);
	m_pbStop->UpdateState();
}

NumberGeneratorScreen::~NumberGeneratorScreen()
{
	std::vector<AElement*>::iterator it = m_elements.begin();
	for (; it != m_elements.end(); ++it)
		if (*it != NULL)
			delete *it;
	m_elements.clear();
}

void NumberGeneratorScreen::Draw(IArgs* _args)
{
	NumberGeneratorArgs* nga = dynamic_cast<NumberGeneratorArgs*>(_args);

	if (m_popUpScreen != NULL)
	{
		m_popUpScreen->Draw(m_popUpArgs);
		return ;
	}

	m_surface.BlitSurface(NULL, nga->Screen, NULL);

	std::vector<AElement*>::iterator it = m_elements.begin();
	for (; it != m_elements.end(); ++it)
	{
		(*it)->Draw(nga->Screen);
	}
}

void NumberGeneratorScreen::Exec(IArgs* _args)
{
	NumberGeneratorArgs* nga = dynamic_cast<NumberGeneratorArgs*>(_args);

	if (m_popUpScreen != NULL)
	{
		m_popUpScreen->Exec(m_popUpArgs);
		return ;
	}

	std::vector<AElement*>::iterator it = m_elements.begin();
	for (; it != m_elements.end(); ++it)
		if (dynamic_cast<AButton*>(*it) != NULL)
			((AButton*)(*it))->UpdateState();

	if (nga->Event->type == SDL_KEYDOWN)
	{
		if (nga->Event->key.keysym.sym == SDLK_ESCAPE)
			nga->Value = 1;
	}
}

static std::string FillZero(Uint32 _value, Uint32 _maximum)
{
	if (_value > _maximum)
		return ("");
	Uint32 value = (_value > 0) ? _value : 1;
	std::string result;

	while (value < _maximum)
	{
		value *= 10;
		if (value < _maximum)
			result += "0";
	}
	return (result);
}

void NumberGeneratorScreen::UpdateTimer(int _seconds)
{
	std::stringstream str;
	int seconds = 0, minutes = 0;

	minutes = _seconds / 60;
	seconds = _seconds % 60;
	if (minutes < 10)
		str << "0";
	str << minutes;
	str << ":";
	if (seconds < 10)
		str << "0";
	str << seconds;
	m_timerLabel->Render(str.str(), Font::RenderBlended);
}

bool NumberGeneratorScreen::Manage(SDL::UTILS::ScreenManager::Element* _caller, SDL::UTILS::IArgs* _arg)
{
	static int last = 0, current = 0;
	NumberGeneratorScreen* ngs = dynamic_cast<NumberGeneratorScreen*>(_caller->Object);

	if (ngs->m_popUpScreen != NULL)
	{
		if (ngs->m_popUpArgs->Value != 0)
		{
			delete ngs->m_popUpScreen;
			delete ngs->m_popUpArgs;
			ngs->m_popUpScreen = NULL;
			ngs->m_popUpArgs = NULL;
		}
	}

	ngs->UpdateConfigLabels();
	std::vector<AElement*>::iterator it = ngs->m_elements.begin();
	for (; it != ngs->m_elements.end(); ++it)
		if (dynamic_cast<AButton*>(*it) != NULL)
			if (((AButton*)(*it))->GetState() == SDL::BUTTON::STATE::CLICKED)
				(ngs->*(ngs->m_actions[*it]))(_caller->Datas, (AButton*)(*it));

	if (ngs->m_generator != NULL)
	{
		current = SDL_GetTicks();

		if (current - last > 1000)
		{
			ngs->m_generator->IncreaseTime();
			ngs->UpdateTimer(ngs->m_generator->GetTime());
			last = current;
		}
		std::stringstream st;
		Uint32 value = ngs->m_generator->Generate();
		st << value;
		ngs->m_valueLabel->Render(FillZero(value, 999) + st.str(), Font::RenderBlended);
		if ((ngs->m_config.Number != 0 && ngs->m_generator->GetNumber() == ngs->m_config.Number)
			|| (ngs->m_config.Time != 0 && ngs->m_generator->GetTime() == ngs->m_config.Time))
		{
			std::vector< std::pair<Uint32, Uint32> > m;
			ngs->m_generator->GetResult(m, 10);
			ngs->m_popUpArgs = new PopUpArgs(((ScreenArgs*)_caller->Datas)->Screen, ((ScreenArgs*)_caller->Datas)->Event);
			ngs->m_popUpScreen = new ResultScreen(ngs->m_generator->GetConfig(), m, ngs->m_generator->GetNumber(), ngs->m_generator->GetTime());
			ngs->Stop();
		}
	}
	else if (last != 0)
	{
		last = 0;
		current = 0;
	}
	return (true);
}

void NumberGeneratorScreen::InitElements()
{
	Rect upperRight(0, 0, m_surface.GetW(), m_surface.GetH());
	Rect pos(32, 32);
	Sint16 x = 0;

	AElement* e = new Label(&m_font, Color((Uint32)0x00FFFFFF));
	((Label*)e)->Render(L"Possibilités:", Font::RenderBlended);
	e->SetPosition(pos);
	m_elements.push_back(e);

	pos.x += e->GetSize().w + 2;
	x = pos.x;
	pos.y -= 4;
	e = new PushButton(L"-", Rect(0, 0, 32, 32));
	e->SetPosition(pos);
	m_elements.push_back(e);
	m_actions[e] = &NumberGeneratorScreen::On_pbPossibilitiesMinus_Clicked;
	
	pos.x += e->GetSize().w + 4;
	pos.y += 4;
	m_possibilitiesLabel = new Label(&m_font, Color((Uint32)0x00FFFFFF));
	m_possibilitiesLabel->Render("000", Font::RenderBlended);
	e = m_possibilitiesLabel;
	e->SetPosition(pos);
	m_elements.push_back(e);

	pos.x += e->GetSize().w + 4;
	pos.y -= 4;
	e = new PushButton(L"+", Rect(0, 0, 32, 32));
	e->SetPosition(pos);
	m_elements.push_back(e);
	m_actions[e] = &NumberGeneratorScreen::On_pbPossibilitiesPlus_Clicked;

	pos.x = 32;
	pos.y += 16 + e->surface->h;

	e = new Label(&m_font, Color((Uint32)0x00FFFFFF));
	((Label*)e)->Render(L"Temps:", Font::RenderBlended);
	e->SetPosition(pos);
	m_elements.push_back(e);

	pos.x = x;
	pos.y -= 4;
	e = new PushButton(L"-", Rect(0, 0, 32, 32));
	e->SetPosition(pos);
	m_elements.push_back(e);
	m_actions[e] = &NumberGeneratorScreen::On_pbTimeMinus_Clicked;
	
	pos.x += e->GetSize().w + 4;
	pos.y += 4;
	m_timeLabel = new Label(&m_font, Color((Uint32)0x00FFFFFF));
	m_timeLabel->Render("0000s", Font::RenderBlended);
	e = m_timeLabel;
	e->SetPosition(pos);
	m_elements.push_back(e);
	
	pos.x += e->GetSize().w + 4;
	pos.y -= 4;
	e = new PushButton(L"+", Rect(0, 0, 32, 32));
	e->SetPosition(pos);
	m_elements.push_back(e);
	m_actions[e] = &NumberGeneratorScreen::On_pbTimePlus_Clicked;

	pos.x = 32;
	pos.y += 16 + e->surface->h;

	e = new Label(&m_font, Color((Uint32)0x00FFFFFF));
	((Label*)e)->Render(L"Nb. tirages:", Font::RenderBlended);
	e->SetPosition(pos);
	m_elements.push_back(e);

	pos.x = x;
	pos.y -= 4;
	e = new PushButton(L"-", Rect(0, 0, 32, 32));
	e->SetPosition(pos);
	m_elements.push_back(e);
	m_actions[e] = &NumberGeneratorScreen::On_pbNbMinus_Clicked;

	pos.x += e->GetSize().w + 4;
	pos.y += 4;
	m_nbLabel = new Label(&m_font, Color((Uint32)0x00FFFFFF));
	m_nbLabel->Render("000000", Font::RenderBlended);
	e = m_nbLabel;
	e->SetPosition(pos);
	m_elements.push_back(e);

	pos.x += e->GetSize().w + 4;
	pos.y -= 4;
	e = new PushButton(L"+", Rect(0, 0, 32, 32));
	e->SetPosition(pos);
	m_elements.push_back(e);
	m_actions[e] = &NumberGeneratorScreen::On_pbNbPlus_Clicked;

	e = new Label(new Font("C:\\Windows\\Fonts\\arial.ttf", 72), Color((Uint32)0x00FFFFFF), true);
	m_valueLabel = (Label*)e;
	m_valueLabel->Render("000", Font::RenderBlended);
	pos.x = m_surface.w / 2 - e->surface->w / 2;
	pos.y = 260;
	e->SetPosition(pos);
	m_elements.push_back(e);

	e = new PushButton(L"Départ");
	m_pbStart = (PushButton*)e;
	pos.x = upperRight.x + (upperRight.w / 2 - ((PushButton*)e)->GetDefaultSize().w / 2);
	pos.y = 380;
	e->SetPosition(pos);
	m_elements.push_back(e);
	m_actions[e] = &NumberGeneratorScreen::On_pbStart_Clicked;

	pos.y += 48;
	e = new PushButton(L"Stop");
	m_pbStop = (PushButton*)e;
	e->SetPosition(pos);
	m_elements.push_back(e);
	m_actions[e] = &NumberGeneratorScreen::On_pbStop_Clicked;
	
	pos.x = m_surface.w - (2 * e->surface->w) - 16;
	pos.y = m_surface.h - e->surface->h - 8;

	e = new PushButton(L"Aide");
	m_pbHelp = (PushButton*)e;
	e->SetPosition(pos);
	m_elements.push_back(e);
	m_actions[e] = &NumberGeneratorScreen::On_pbHelp_Clicked;

	pos.x += e->surface->w + 8;
	e = new PushButton(L"Retour");
	m_pbBack = (PushButton*)e;
	e->SetPosition(pos);
	m_elements.push_back(e);
	m_actions[e] = &NumberGeneratorScreen::On_pbBack_Clicked;

	e = new Label(new Font("C:\\Windows\\Fonts\\arial.ttf", 72), Color((Uint32)0x00FFFFFF), true);
	((Label*)e)->Render(L"00:00", Font::RenderBlended);
	m_timerLabel = (Label*)e;
	pos.x = upperRight.w - e->GetSize().w - 16;
	pos.y = 16;
	e->SetPosition(pos);
	m_elements.push_back(e);
}

void NumberGeneratorScreen::UpdateConfigLabels()
{
	static NGConfig lastConfig(0, 0, 0);

	if (lastConfig != m_config)
	{
		{
			std::stringstream st;
			st << m_config.Possibilities;
			m_possibilitiesLabel->Render(FillZero(m_config.Possibilities, 999) + st.str(), Font::RenderBlended);
		}

		{
			std::stringstream st;
			st << m_config.Time;
			m_timeLabel->Render(FillZero(m_config.Time, 9999) + st.str() + "s", Font::RenderBlended);
		}

		{
			std::stringstream st;
			st << m_config.Number;
			m_nbLabel->Render(FillZero(m_config.Number, 999999) + st.str(), Font::RenderBlended);
		}

		lastConfig = m_config;
	}
}

void NumberGeneratorScreen::Start()
{
	m_generator = new NumberGenerator(m_config);

	std::vector<AElement*>::iterator it = m_elements.begin();
	for (; it != m_elements.end(); ++it)
	{
		if (dynamic_cast<AButton*>(*it) != NULL)
		{
			((AButton*)(*it))->SetDisabled(true);
			((AButton*)(*it))->UpdateState();
		}
	}
	m_pbStop->SetDisabled(false);
	m_pbStop->UpdateState();
}

void NumberGeneratorScreen::Stop()
{
	delete m_generator;
	m_generator = NULL;
	m_valueLabel->Render("000", Font::RenderBlended);
	this->UpdateTimer(0);

	std::vector<AElement*>::iterator it = m_elements.begin();
	for (; it != m_elements.end(); ++it)
	{
		if (dynamic_cast<AButton*>(*it) != NULL)
		{
			((AButton*)(*it))->SetDisabled(false);
			((AButton*)(*it))->UpdateState();
		}
	}
	m_pbStop->SetDisabled(true);
	m_pbStop->UpdateState();
}

void NumberGeneratorScreen::Reset()
{
}

void NumberGeneratorScreen::ShowResultScreen()
{
}

bool NumberGeneratorScreen::On_pbPossibilitiesMinus_Clicked(SDL::UTILS::IArgs* _datas, AButton* _button)
{
	m_config.Possibilities--;
	if (m_config.Possibilities < 2)
		m_config.Possibilities = 999;
	_button->SetState(SDL::BUTTON::RELEASED);
	return (true);
}

bool NumberGeneratorScreen::On_pbPossibilitiesPlus_Clicked(SDL::UTILS::IArgs* _datas, AButton* _button)
{
	m_config.Possibilities++;
	if (m_config.Possibilities > 999)
		m_config.Possibilities = 2;
	_button->SetState(SDL::BUTTON::RELEASED);
	return (true);
}

bool NumberGeneratorScreen::On_pbTimeMinus_Clicked(SDL::UTILS::IArgs* _datas, AButton* _button)
{
	m_config.Number = 0;
	if (m_config.Time == 0)
		m_config.Time = 9990;
	else
		m_config.Time -= 10;
	_button->SetState(SDL::BUTTON::RELEASED);
	return (true);
}

bool NumberGeneratorScreen::On_pbTimePlus_Clicked(SDL::UTILS::IArgs* _datas, AButton* _button)
{
	m_config.Number = 0;
	if (m_config.Time == 9990)
		m_config.Time = 0;
	else
		m_config.Time += 10;
	_button->SetState(SDL::BUTTON::RELEASED);
	return (true);
}

bool NumberGeneratorScreen::On_pbNbMinus_Clicked(SDL::UTILS::IArgs* _datas, AButton* _button)
{
	m_config.Time = 0;
	if (m_config.Number == 0)
		m_config.Number = 999900;
	else
		m_config.Number -= 100;
	_button->SetState(SDL::BUTTON::RELEASED);
	return (true);
}

bool NumberGeneratorScreen::On_pbNbPlus_Clicked(SDL::UTILS::IArgs* _datas, AButton* _button)
{
	m_config.Time = 0;
	if (m_config.Number == 999900)
		m_config.Number = 0;
	else
		m_config.Number += 100;
	_button->SetState(SDL::BUTTON::RELEASED);
	return (true);
}

bool NumberGeneratorScreen::On_pbStart_Clicked(SDL::UTILS::IArgs* _datas, AButton* _button)
{
	_button->SetState(SDL::BUTTON::RELEASED);
	this->Start();
	return (true);
}

bool NumberGeneratorScreen::On_pbStop_Clicked(SDL::UTILS::IArgs* _datas, AButton* _button)
{
	_button->SetState(SDL::BUTTON::RELEASED);
	ScreenArgs* sa = dynamic_cast<ScreenArgs*>(_datas);

	std::vector< std::pair<Uint32, Uint32> > m;
	m_generator->GetResult(m, 10);
	m_popUpArgs = new PopUpArgs(sa->Screen, sa->Event);
	m_popUpScreen = new ResultScreen(m_generator->GetConfig(), m, m_generator->GetNumber(), m_generator->GetTime());
	this->Stop();
	return (true);
}

bool NumberGeneratorScreen::On_pbBack_Clicked(SDL::UTILS::IArgs* _datas, AButton* _button)
{
	NumberGeneratorArgs* nga = dynamic_cast<NumberGeneratorArgs*>(_datas);
	
	nga->Value = 1;
	return (true);
}

bool NumberGeneratorScreen::On_pbHelp_Clicked(SDL::UTILS::IArgs* _datas, AButton* _button)
{
	if (_button != NULL)
		_button->SetState(SDL::BUTTON::RELEASED);
	ScreenArgs* sa = dynamic_cast<ScreenArgs*>(_datas);
	if (sa == NULL)
		return (false);
	m_popUpArgs = new PopUpArgs(sa->Screen, sa->Event);
	m_popUpScreen = new HelpScreen();
	return (true);
}
